#include "asio_driver/io/spi.hpp"
#include <cassert>
#include <cstdint>
#include <cstring>
#include <errno.h>
#include <fcntl.h>
#include <linux/spi/spi.h>
#include <linux/spi/spidev.h>
#include <linux/types.h>
#include <stdexcept>
#include <sys/ioctl.h>
#include <sys/types.h>
#include <unistd.h>

namespace AD
{
Spi::~Spi()
{
    if (isOpen)
    {
        Close();
    }
}

bool Spi::SetSpeed(uint32_t speed)
{
    assert(fd > 0);
    return -1 != ioctl(fd, SPI_IOC_WR_MAX_SPEED_HZ, &speed);
}

bool Spi::SetBitWidth(uint8_t width)
{
    assert(fd > 0);
    return -1 != ioctl(fd, SPI_IOC_WR_BITS_PER_WORD, &width);
}
bool Spi::SetMode(SPIMODE mode)
{
    assert(fd > 0);
    return -1 != ioctl(fd, SPI_IOC_WR_MODE, mode);
}

bool Spi::Open(const std::string &dev)
{
    fd = open(dev.c_str(), O_RDWR);
    if (fd < 0)
        throw std::runtime_error("Failed to open " + dev + " with error: " + strerror(errno));
    isOpen = true;
    return isOpen;
}

bool Spi::Close()
{
    isOpen = false;
    return -1 != close(fd);
}

bool Spi::Send(std::span<const unsigned char> data)
{
    return -1 != write(fd, data.data(), data.size());
}
} // namespace AD